import { _decorator, Component, director, Node } from 'cc'
import { DIRECTION_ENUM, ENTITY_STATE_ENUM, ENTITY_TYPE_ENUM, EVENT_ENUM, SCENE_ENUM } from '../../Enums'
import levels, { ILevel } from '../../Levels'
import DataManager, { IRecord } from '../../Runtime/DataManager'
import EventManager from '../../Runtime/EventManager'
import { createUINode } from '../../utils'
import { TILE_HEIGHT, TILE_WIDTH } from '../../utils/constant'
import { BurstManager } from '../Burst/BurstManager'
import { DoorManager } from '../Door/DoorManager'
import { IronSkeletonManager } from '../IronSkeleton/IronSkeletonManager'
import { PlayerManager } from '../Player/PlayerManager'
import { SpikesManager } from '../Spikes/SpikesManager'
import { TileMapManager } from '../Tile/TileMapManager'
import { WoodenSkeletonManager } from '../WoodenSkeleton/WoodenSkeletonManager'
import { SmokeManager } from '../Smoke/SmokeManager'
import FaderManager from '../../Runtime/FaderManager'
import { ShakeManager } from '../UI/ShakeManager'

const { ccclass } = _decorator

@ccclass('BattleManager')
export class BattleManager extends Component {
  level: ILevel
  stage: Node
  private smokeLayer: Node
  private isInited: boolean = false

  onLoad() {
    DataManager.Instance.levelIndex = 1
    EventManager.Instance.on(EVENT_ENUM.NEXT_LEVEL, this.nextLevel, this)
    EventManager.Instance.on(EVENT_ENUM.PLAYER_MOVE_END, this.checkArrived,this)
    EventManager.Instance.on(EVENT_ENUM.SHOW_SMOKE, this.generateSmoke,this)
    EventManager.Instance.on(EVENT_ENUM.RECORD_STEP, this.record,this)
    EventManager.Instance.on(EVENT_ENUM.REVOKE_STEP, this.revoke,this)
    EventManager.Instance.on(EVENT_ENUM.RESTART_LEVEL, this.initLevel,this)
    EventManager.Instance.on(EVENT_ENUM.OUT_BATTLE, this.outBattle,this)
  }

  onDestroy() {
    EventManager.Instance.off(EVENT_ENUM.NEXT_LEVEL, this.nextLevel)
    EventManager.Instance.off(EVENT_ENUM.PLAYER_MOVE_END, this.checkArrived)
    EventManager.Instance.off(EVENT_ENUM.SHOW_SMOKE, this.generateSmoke)
    EventManager.Instance.off(EVENT_ENUM.RECORD_STEP, this.record)
    EventManager.Instance.off(EVENT_ENUM.REVOKE_STEP, this.revoke)
    EventManager.Instance.off(EVENT_ENUM.RESTART_LEVEL, this.initLevel)
    EventManager.Instance.off(EVENT_ENUM.OUT_BATTLE, this.outBattle)
  }

  start() {
    this.generateStage()
    this.initLevel()
  }

  async outBattle() {
    await FaderManager.Instance.fadeIn()
    director.loadScene(SCENE_ENUM.START)
  }

  async initLevel() {
    const levelIndex = DataManager.Instance.levelIndex
    const level = levels[`level${levelIndex}`]
    if (level) {
      if(this.isInited) {
        await FaderManager.Instance.fadeIn()
      } else {
        await FaderManager.Instance.mask()
      }
      this.clearLevel()
      this.level = level

      // 存储到数据中心
      DataManager.Instance.mapInfo = this.level.mapInfo
      DataManager.Instance.mapRowCount = this.level.mapInfo.length || 0
      DataManager.Instance.mapColCount = this.level.mapInfo[0].length || 0

      await Promise.all([
        this.generateTileMap(),
        this.generateBursts(),
        this.generateSpikes(),
        this.generateSmokeLayer(),
        this.generateDoor(),
        this.generateEnemies(),
      ])

      await this.generatePlayer()

      await FaderManager.Instance.fadeOut()
      this.isInited = true
    } else {
      this.outBattle()
    }
  }

  // 生成舞台（场景）
  async generateStage() {
    this.stage = createUINode()
    this.stage.setParent(this.node)
    this.stage.addComponent(ShakeManager)
  }

  // 生成地图
  async generateTileMap() {
    const tileMap = createUINode()
    tileMap.setParent(this.stage)

    const tileMapManager = tileMap.addComponent(TileMapManager)
    await tileMapManager.init()

    this.adaptPos()
  }

  // 生成玩家
  async generatePlayer() {
    const player = createUINode()
    player.setParent(this.stage)

    const playerManager = player.addComponent(PlayerManager)
    DataManager.Instance.player = playerManager
    await playerManager.init(this.level.player)
    // 触发玩家出生事件
    EventManager.Instance.emit(EVENT_ENUM.PLAYER_BORN, true)
  }

  // 生成敌人
  async generateEnemies() {
    const promise = []
    for (let i = 0; i < this.level.enemies.length; i++) {
      const enemy = this.level.enemies[i]
      const node = createUINode()
      node.setParent(this.stage)
      const Manager = enemy.type === ENTITY_TYPE_ENUM.WOODEN_SKELETON ? WoodenSkeletonManager : IronSkeletonManager
      const manager = node.addComponent(Manager)
      // manager.init(enemy)是一个异步操作，这里统一放入一个promise数组中，避免每次循环都要等待。等到循环结束后，再一起执行
      promise.push(manager.init(enemy))
      DataManager.Instance.enemies.push(manager)
    }

    await Promise.all(promise)
  }


  // 生成地陷
  async generateBursts() {
    const promise = []
    for (let i = 0; i < this.level.bursts.length; i++) {
      const burst = this.level.bursts[i]
      const node = createUINode()
      node.setParent(this.stage)
      const manager = node.addComponent(BurstManager)
      promise.push(manager.init(burst))
      DataManager.Instance.bursts.push(manager)
    }

    await Promise.all(promise)
  }

  // 生成地刺
  async generateSpikes() {
    const promise = []
    for (let i = 0; i < this.level.spikes.length; i++) {
      const spikes = this.level.spikes[i]
      const node = createUINode()
      node.setParent(this.stage)
      const manager = node.addComponent(SpikesManager)
      promise.push(manager.init(spikes))
      DataManager.Instance.spikes.push(manager)
    }

    await Promise.all(promise)
  }

  // 生成门
  async generateDoor() {
    const door = createUINode()
    door.setParent(this.stage)

    const doorManager = door.addComponent(DoorManager)
    await doorManager.init(this.level.door)
    DataManager.Instance.door = doorManager
  }

  // 适配位置
  adaptPos() {
    const { mapRowCount, mapColCount } = DataManager.Instance
    const disX = TILE_WIDTH * (mapColCount / 2)
    const disY = TILE_HEIGHT * (mapRowCount / 2) + 80
    this.stage.getComponent(ShakeManager).stop()
    this.stage.setPosition(-disX, disY)
  }

  // 下一关
  async nextLevel() {
    DataManager.Instance.levelIndex++

    // 添加通关判断
    if (DataManager.Instance.levelIndex > 21) {
      console.log('恭喜通关！')
      // 处理通关逻辑
      return
    }

    await this.initLevel()
  }

  // 清除关卡
  clearLevel() {
    this.stage.destroyAllChildren()
    DataManager.Instance.reset()
  }

  // 检查玩家是否到达门的位置
  checkArrived() {
    const { x: playerX, y: playerY } = DataManager.Instance.player
    const { x: doorX, y: doorY, state:doorState } = DataManager.Instance.door
    if(playerX === doorX && playerY === doorY && doorState === ENTITY_STATE_ENUM.DEATH){
      EventManager.Instance.emit(EVENT_ENUM.NEXT_LEVEL)
    }
  }

  generateSmokeLayer() {
    this.smokeLayer = createUINode()
    this.smokeLayer.setParent(this.stage)
  }

  // 生成烟雾
  async generateSmoke(x: number, y: number, direction: DIRECTION_ENUM) {
    // 性能优化：从DataManager中获取烟雾,避免一直创建
    const smoke = DataManager.Instance.smokes.find(somke => somke.state === ENTITY_STATE_ENUM.DEATH)
    if(smoke){
      smoke.x = x
      smoke.y = y
      smoke.direction = direction
      smoke.state = ENTITY_STATE_ENUM.IDLE
      smoke.node.setPosition(x * TILE_WIDTH - TILE_WIDTH * 1.5, -y * TILE_HEIGHT + TILE_HEIGHT * 1.5)
    } else {

      const somke = createUINode()
      somke.setParent(this.smokeLayer)
      const smokeManager = somke.addComponent(SmokeManager)
      await smokeManager.init({
        x,
        y,
        direction,
        type:ENTITY_TYPE_ENUM.SMOKE,
        state:ENTITY_STATE_ENUM.IDLE
      })

      DataManager.Instance.smokes.push(smokeManager)
    }
  }

  // 记录当前关卡信息
  record() {
    const item: IRecord = {
      player: {
        x: DataManager.Instance.player.x,
        y: DataManager.Instance.player.y,
        type: DataManager.Instance.player.type,
        direction: DataManager.Instance.player.direction,
        state:
          DataManager.Instance.player.state === ENTITY_STATE_ENUM.IDLE ||
          DataManager.Instance.player.state === ENTITY_STATE_ENUM.DEATH ||
          DataManager.Instance.player.state === ENTITY_STATE_ENUM.AIR_DEATH
          ? DataManager.Instance.player.state
          : ENTITY_STATE_ENUM.IDLE
      },
      door: {
        x: DataManager.Instance.door.x,
        y: DataManager.Instance.door.y,
        type: DataManager.Instance.door.type,
        direction: DataManager.Instance.door.direction,
        state: DataManager.Instance.door.state
      },
      enemies: DataManager.Instance.enemies.map(({x,y,type,direction,state}) => ({
        x,
        y,
        type,
        direction,
        state
      })),
      bursts: DataManager.Instance.bursts.map(({x,y,type,direction,state}) => ({
        x,
        y,
        type,
        direction,
        state
      })),
      spikes: DataManager.Instance.spikes.map(({x,y,count,type}) => ({
        x,
        y,
        count,
        type
      }))
    }

    DataManager.Instance.records.push(item)
  }

  // 撤回数据
  revoke() {
    const item = DataManager.Instance.records.pop()

    if(item) {
      const {player,door,enemies,bursts,spikes} = item
      // player
      DataManager.Instance.player.x = DataManager.Instance.player.targetX = player.x
      DataManager.Instance.player.y = DataManager.Instance.player.targetY = player.y
      DataManager.Instance.player.direction = player.direction
      DataManager.Instance.player.state = player.state
      DataManager.Instance.player.type = player.type

      // door
      DataManager.Instance.door.x = door.x
      DataManager.Instance.door.y = door.y
      DataManager.Instance.door.direction = door.direction
      DataManager.Instance.door.state = door.state
      DataManager.Instance.door.type = door.type

      // enemies
      DataManager.Instance.enemies.forEach((enemy, index) => {
        enemy.x = enemies[index].x
        enemy.y = enemies[index].y
        enemy.direction = enemies[index].direction
        enemy.state = enemies[index].state
        enemy.type = enemies[index].type
      })

      // bursts
      DataManager.Instance.bursts.forEach((burst, index) => {
        burst.x = bursts[index].x
        burst.y = bursts[index].y
        burst.state = bursts[index].state
        burst.type = bursts[index].type
      })

      // spikes
      DataManager.Instance.spikes.forEach((spike, index) => {
        spike.x = spikes[index].x
        spike.y = spikes[index].y
        spike.count = spikes[index].count
        spike.type = spikes[index].type
      })
    }
  }
}
